package com.apes.framework.condition;

import com.apes.framework.api.ApesParser;
import com.apes.framework.jpa.Connector;
import com.apes.framework.plugin.cache.MemoryCache;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.filereader.xml.ApesElement;
import com.apes.framework.plugin.filereader.xml.SimpleApesElement;
import com.apes.framework.plugin.form.parser.element.*;
import com.apes.framework.query.lib.PubToolUtil;
import com.apes.framework.util.MapUtil;
import com.apestech.api.condition.ConditionExec;
import com.apestech.api.condition.ConditionStrategyExec;
import com.apestech.api.xml.esb.modul.EsbForm;
import com.apestech.formwork.condition.ConditionUtil;
import com.apestech.framework.db.SqlSession;
import com.apestech.framework.json.JSON;
import com.apestech.framework.json.JSONArray;
import com.apestech.framework.json.JSONObject;
import com.apestech.framework.sql.ReportSql;
import com.apestech.framework.util.DBUtil;
import com.apestech.framework.util.DateUtil;
import com.apestech.framework.xml.condition.modul.Condition;
import org.bson.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Service;

import java.sql.Connection;
import java.sql.SQLException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Service("conditionService")
public class ConditionService extends PubToolUtil {
    @Autowired
    Connector connector;
    @Autowired
    private MongoTemplate mongoTemplate;

    //synchronized
    public JSONObject execConditionStrategy(SimpleRequest param) throws RuntimeException {
        try {
            JSONObject json= getInput(param);
            Connection connection= connector.getConnection();
            SqlSession session=getSession(connection);
            saveLog("开始执行：DbName : " + session.getDbName()+ "   NUM ->  "+session.getDataSource().getActiveCount());
            ConditionStrategyExec exec=new ConditionStrategyExec(session, json.getString("conditionStrategyId"));
            exec.setInput(json);
            exec.expain();
            saveLog("执行结束：DbName : " + session.getDbName()+ "   NUM ->  "+session.getDataSource().getActiveCount());
            return exec.getResultMap();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private void saveLog(String remark) {
        Document document = new Document();
        document.put("remark", remark);
        document.put("date", LocalDateTime.now());
        mongoTemplate.getCollection("tcConnection").insertOne(document);
    }

    public synchronized JSONObject execConditionStrategy_trans(SimpleRequest param) throws RuntimeException {
        Connection connection=null;
        try {
            JSONObject json= getInput(param);
            SqlSession session=getSession_S();
            connection= session.getDataSource().getConnection();
            session.setConnection(connection);
            ConditionStrategyExec exec=new ConditionStrategyExec(session, json.getString("conditionStrategyId"));
            exec.setInput(json);
            connection.setAutoCommit(false);
            exec.expain();
            connection.commit();
            return exec.getResultMap();
        } catch (Exception e) {
            try {
                connection.rollback();
            } catch (SQLException ex) {
                throw new RuntimeException(ex);
            }
            throw new RuntimeException(e);
        } finally {
            try {
                connection.close();
            } catch (SQLException ex) {
                throw new RuntimeException(ex);
            }
        }
    }

    public JSONObject getCondition(SimpleRequest param) throws RuntimeException {
        try {
            JSONObject json= getInput(param);
            Connection connection= connector.getConnection();
            SqlSession session=getSession(connection);
            ConditionExec exec=new ConditionExec(session, json.getString("conditionId"));
            return exec.getCondition(json);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public JSONArray getCondition_Muti(SimpleRequest param) throws RuntimeException {
        try {
            JSONObject json= getInput(param);
            Connection connection= connector.getConnection();
            SqlSession session=getSession(connection);
            ConditionExec exec=new ConditionExec(session, json.getString("conditionId"));
            return exec.getConditionFromMutiData(json);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public String qryConditionMidTabName(SimpleRequest param) throws RuntimeException {
        try {
            JSONObject json= getInput(param);
            Connection connection= connector.getConnection();
            SqlSession session=getSession(connection);
            ConditionExec exec=new ConditionExec(session, json.getString("conditionId"));
            return exec.qryConditionMidTabName(json);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public void report(SimpleRequest param) throws RuntimeException {
        try {
            JSONObject json= getInput(param);
            String reportId =json.getString("reportId");
            String TJRQ_STAR =json.getString("TJRQ_STAR");
            String TJRQ_END =json.getString("TJRQ_END");
            json.put("TJRQ_STAR", DateUtil.strToDate(TJRQ_STAR));
            json.put("TJRQ_END", DateUtil.strToDate(TJRQ_END));
            if(reportId==null){
                throw new RuntimeException("reportId不能为空，请补全！");
            }
            SqlSession session=getSession(DBUtil.getSysSingleDBName("ESB"), connector.getConnection());
            ReportSql report=new ReportSql(session);
            report.execute(reportId,json);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public JSONArray getForm(SimpleRequest request) throws RuntimeException {
        try {
            Connection connection = connector.getConnection();
            SqlSession session = getSession(connection);
            EsbForm esb = new EsbForm();
            String id = request.get("ID");
            String tabId = request.get("MID");
            Condition condition= ConditionUtil.getCondition(id, session);
            JSONArray list=esb.getConditionField(condition, tabId, null);
            JSONObject map=new JSONObject();
            map.put("tag", condition.getTag());
            list.add(map);
            return list;
            //JSONObject formData = esb.getConditionFields(condition, tabId, null);
            //return getFormConfig(formData.getJSONArray("master"),formData.getJSONArray("detail"));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public List<Map> getFormQuery(SimpleRequest request) throws RuntimeException {
        try {
            Connection connection = connector.getConnection();
            SqlSession session = getSession(connection);
            EsbForm esb = new EsbForm();
            esb.setSession(session);
            String id = request.get("ID");
            String tabId = request.get("MID");
            String query = request.get("query");
            Condition condition= ConditionUtil.getCondition(id, session);
            JSONObject input=new JSONObject();
            input.put("query", query);
            JSONObject formData = esb.getQryConditionField_esb(condition, tabId, input,null);
            return getFormQueryConfig(formData.getJSONArray("master"),formData.getJSONArray("detail"), query);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取定价过程下拉框数据
     * @param request
     * @throws RuntimeException
     */
    public Map getPriceProcessSelectData(SimpleRequest request) throws RuntimeException {
        try {
            JSONObject input=PubToolUtil.getInput(request);
            String key=input.getString("key");
            String id=input.getString("ID");
            String name=input.getString("NAME");
            Connection connection = connector.getConnection();
            SqlSession session = getSession(connection);
            List<Map> maps = MapUtil.mapped(ConditionUtil.getConditionStrategy(session, key, id, name));
            return MapUtil.mapper("pages", 1, "page", 0, "content", maps);  //"total", maps.size(), , "size", maps.size()
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取定价过程页面查询条件
     * @param request
     * @return
     * @throws RuntimeException
     */
    public List<Map> getPriceProcessForm(SimpleRequest request) throws RuntimeException {
        try {
            Connection connection = connector.getConnection();
            SqlSession session = getSession(connection);
            ConditionStrategyExec exec=new ConditionStrategyExec(session, request.get("ID"));
            exec.setInput(new JSONObject());
            EsbForm esb=new EsbForm();
            JSONObject formData = esb.getStrategyFields(exec);
            return getPriceProcessFormConfig(formData.getJSONArray("master"),"query");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 验证定价过程查询
     * @param request
     * @return
     */
    public synchronized Map priceProcessQuery(SimpleRequest request){
        try{
            List<Map> filters = request.get("condition");
            Map input = new HashMap();
            input.put("SYS_RQ",new Date());
            for (Map filter : filters) {
                input.put(filter.get("field"), filter.get("value"));
            }
            Connection connection = connector.getConnection();
            SqlSession session = getSession(connection);
            ConditionStrategyExec exec=new ConditionStrategyExec(session, (String) input.get("EXE_PRICE_PROCESS"));
            exec.setInput(new JSONObject(input));
            exec.expain();
            System.out.println(JSON.toJSONString(exec.getStepInfo()));
            return MapUtil.mapper("content", exec.getStepInfo());
        }catch (Exception e) {
            throw new RuntimeException(e);
        }
//        return null;
    }

    public List<Map> getFormConfig(JSONArray masterArray,JSONArray detailArray){
        // 设置解析器
        // sheet > group > field
        ApesElement sheetElement = createApesElement("sheet", new SheetElementParser());
        ApesParser groupParser = new GroupElementParser();
        ApesElement mainGroupElement = createApesElement("group", groupParser);
        mainGroupElement.setParent(sheetElement);
        mainGroupElement.setAttribute("bodyStyle", "{'padding':0,'margin-top':'-16px'}");
        sheetElement.setNestedElement(mainGroupElement);

        // sheet > tabs > tab > table > field
        ApesParser tabsParser = new TabsElementParser();
        ApesElement itemsGroupElement = createApesElement("tabs", tabsParser);
        ApesParser tabParser = new TabElementParser();
        ApesElement tabElemElement = createApesElement("tab", tabParser);
        tabElemElement.setAttribute("title", "策略明细");
        tabElemElement.setParent(itemsGroupElement);
        ApesElement tableElement = createApesElement("table", new TableElementParser());
        tableElement.setParent(itemsGroupElement);
        tableElement.setAttribute("domLayout", "autoHeight");
        tableElement.setAttribute("name", "ITEMS");
        tableElement.setAttribute("required", "true");
        tableElement.setAttribute("disabled", "ctx.states === 'new'");
        tableElement.setParent(tabElemElement);
        itemsGroupElement.setParent(sheetElement);
        itemsGroupElement.setNestedElement(tabElemElement);
        tabElemElement.setNestedElement(tableElement);
        sheetElement.setNestedElement(itemsGroupElement);

        ApesParser fieldParser = new FieldElementParser();

        masterArray.stream().forEach(o -> {
            HashMap map = new HashMap((JSONObject) o);
            ApesElement fieldElement = createApesElement("field",fieldParser);
            setFiledElementAttribute(map,fieldElement,"form",null);
            isMainOrItems(true, mainGroupElement, tableElement, fieldElement);
        });

        //表格明细解析器
        ApesParser tableParser = new TableElementParser();
        detailArray.stream().forEach(o -> {
            HashMap map = new HashMap((JSONObject) o);
            ApesElement fieldElement = createApesElement("field",fieldParser);
            setFiledElementAttribute(map,fieldElement,"form",null);
            isMainOrItems(false, mainGroupElement, tableElement, fieldElement);
        });


        List<Map> map = sheetElement.parse();
        MemoryCache.getInstance().put("tech." + "pricingStrategyOrder", map);
        return map;
    }

    /**
     * 表单查询页面
     * @param masterArray 主数据
     * @param detailArray 明细数据
     * @param query
     * @return
     */
    public List<Map> getFormQueryConfig(JSONArray masterArray,JSONArray detailArray,String query){
        // 设置解析器
        // search > field
        ApesElement searchElement = createApesElement("search", new SearchElementParser());

        ApesParser fieldParser = new FieldElementParser();

        masterArray.stream().forEach(o -> {
            HashMap map = new HashMap((JSONObject) o);
            ApesElement fieldElement = createApesElement("field",fieldParser);
            setFiledElementAttribute(map,fieldElement,"search",query);
            isMainOrItems(true, searchElement, null, fieldElement);

//            fieldElement = createApesElement("field",fieldParser);
//            fieldElement.setAttribute("label", "状态");
//            fieldElement.setAttribute("widget", "select");
//            fieldElement.setAttribute("valueFormatter","value? ('[' + value.id + ']' + value.name):''");
//            fieldElement.setAttribute("downFormatter","value? ('[' + value.id + ']' + value.name):''");
//            fieldElement.setAttribute("divCol","12");
//            fieldElement.setAttribute("domain","[('sysField', '=', 'STATE')]");
//            fieldElement.setAttribute("required","false");
//            fieldElement.setAttribute("init","true");
//            fieldElement.setAttribute("placeholder","请选择状态");
//            fieldElement.setAttribute("config_type","select");
//            fieldElement.setAttribute("api","strategy.getDownData");
//            fieldElement.setAttribute("name","STATE");
//            fieldElement.setAttribute("operators","=");
//            fieldElement.setParent(searchElement);
//            searchElement.setNestedElement(fieldElement);
        });

        //设置表格解析器
        // Tables > table > field
        ApesElement tablesElement = createApesElement("tables", new TablesElementParser());
        ApesElement tableElement = createApesElement("table", new TableElementParser());

        detailArray.stream().forEach(o -> {
            HashMap map = new HashMap((JSONObject) o);
            ApesElement fieldElement = createApesElement("field",fieldParser);
            setFiledElementAttribute(map,fieldElement,"search",query);
            isMainOrItems(false, searchElement, tableElement, fieldElement);
        });

//        fieldElement = createApesElement("field",fieldParser);
//        fieldElement.setAttribute("name", "Z_ID");
//        fieldElement.setAttribute("label", "策略编码");
//        fieldElement.setAttribute("headerName","计费支援申请单号");
//        fieldElement.setParent(tableElement);
//        tableElement.setNestedElement(fieldElement);

        tablesElement.setNestedElement(tableElement);
        tableElement.setParent(tablesElement);

        //解析
        List<Map> maps = new ArrayList<>();

        Map map = new HashMap();
        map.put("conditionField",searchElement.parse());
        map.put("domain","{\"table_id\":\"condition\"}");

        maps.add(map);
        maps.addAll(tablesElement.parse());

        MemoryCache.getInstance().put("strategy." + "queryTab", map);
        return maps;
    }

    /**
     * 定价过程页面配置
     * @param masterArray 主数据
     */
    public List<Map> getPriceProcessFormConfig(JSONArray masterArray,String query){
        // 设置解析器
        // search > field
        ApesElement searchElement = createApesElement("search", new SearchElementParser());

        ApesParser fieldParser = new FieldElementParser();

        masterArray.stream().forEach(o -> {
            HashMap map = new HashMap((JSONObject) o);
            ApesElement fieldElement = createApesElement("field",fieldParser);
            setFiledElementAttribute(map,fieldElement,"search",query);
            isMainOrItems(true, searchElement, null, fieldElement);
        });

        //解析
        List<Map> maps = new ArrayList<>();

        Map map = new HashMap();
        map.put("conditionField",searchElement.parse());
        maps.add(map);

        MemoryCache.getInstance().put("tech.pricingProcess.query", maps);
        return maps;
    }



    /**
     * 设置字段属性
     * @param map
     * @param fieldElement
     * @param type 区分是制单还是查询
     */
    private void setFiledElementAttribute(HashMap map,ApesElement fieldElement,String type,String query){
        for (Object o : map.keySet()){
            String key = String.valueOf(o);
            String value = String.valueOf(map.get(o));

            if("search".equals(type)){
                if ("config_type".equals(key)){
                    fieldElement.setAttribute("widget",value);
                }else if("operators".equals(key)){
                    fieldElement.setAttribute("operators",value.replaceAll("\\[","").replaceAll("]",""));
                }else if("type".equals(key)){
                    //TODO 暂时用不上
                }else if("field".equals(key)){
                    fieldElement.setAttribute("field",value);
                    fieldElement.setAttribute("name",value);
                }else if("divCol".equals(key) && !query.equals("billpop")){
                    //TODO 查询报表不设置这个属性
                }else if("searchFormId".equals(key)){
                    fieldElement.setAttribute("searchFormId",value);
                    fieldElement.setAttribute("addSame","false");
                    fieldElement.setAttribute("uniqueKey","ID");
                    fieldElement.setAttribute("init","true");
                }else{
                    fieldElement.setAttribute(key,value);;
                }
            }else {
                if ("type".equals(key)){
                    fieldElement.setAttribute("widget",value);
                }else if("field".equals(key)){
                    fieldElement.setAttribute("field",value);
                    fieldElement.setAttribute("name",value);
                }else{
                    fieldElement.setAttribute(key,value);
                }
            }
        }
    }

    /**
     * 生成对应的xml 解析控件
     * @param apesType  控件名称
     * @param apesParser 控件解析器
     */
    private ApesElement createApesElement(String apesType, ApesParser apesParser) {
        ApesElement apesElement = new SimpleApesElement();
        apesElement.setName(apesType);
        apesElement.setParser(apesParser);
        return apesElement;
    }

    /**
     * 添加到主表还是明细
     * @param isMain 是否主表
     * @param mainElement 主表
     * @param itemsElement 明细
     * @param fieldElement 字段
     */
    private void isMainOrItems(boolean isMain, ApesElement mainElement, ApesElement itemsElement, ApesElement fieldElement) {
        if (isMain) {
            fieldElement.setParent(mainElement);
            mainElement.setNestedElement(fieldElement);
        } else {
            fieldElement.setParent(itemsElement);
            itemsElement.setNestedElement(fieldElement);
        }
    }

    /**
     * 根据条件编码获取
     */
    public Map getConditionById(SimpleRequest request) throws RuntimeException {
        try {
            String ID = request.get("ID");
            SqlSession session=getSession(connector.getConnection());
            //JSONArray condition = ConditionUtil.getCondition(session);
            return MapUtil.mapped(ConditionUtil.getCondition(session).stream().filter(map -> {
                return ((JSONObject) map).get("ID").equals(ID);
            }).collect(Collectors.toList()).stream().findFirst().get());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
